案例名称:课程表查询系统
案例编号:C5
涉及的知识点编号:
涉及的基础实验编号:
作者:中原工学院 刘凤华
一、 项目整体概述
根据登录信息获取校园网上的课程信息并个性化形式显示,方便在校学生查看本班课程表和个人课程信息。
二、 方案设计
主要技术点包括:创建工程、网络服务技术应用、 模拟校园网登录、 多线程应用、 AsyncTask异步处理技术应用、jsoup爬取网站信息技术应用等
三、 系统开发步骤
1、任务编号:C5-001 加载项目工程
1.1、相关知识点
Android的目录结构
1.2、任务描述
前置任务:无
业务模块:主视图界面
创建一个新的Android工程。
任务类型:按要求写代码(功能实现)
1.3、详细实现步骤
创建一个Android项目。
- 取名”KB”。
- 在工程res文件夹中新建drawable文件夹。
- 将当前实训场景中的素材文件夹中的素材复制入drawable文件夹。
2、任务编号:C5-002 发布Android项目
2.1、相关知识点
发布Android项目录
2.2、任务描述
前置任务:C5-001
业务模块:主视图界面
1、修改项目图标并通过Eclipse部署项目。
任务类型:按要求写代码(功能实现)
2、将APK文件通过adb指令部署入模拟器或手机中。
任务类型:按要求写代码(功能实现)
2.3、详细实现步骤
1、修改项目图标并通过Eclipse部署项目。
- 通过AndroidMainfest.xml文件修改图标资源。
- 设定当前应用的图标为tb.png。
- 运行模拟器。
- 将当前应用部署入模拟器。
2、 将APK文件通过adb指令部署入模拟器或手机中。
- 在Windows的控制台上通过adb指令安装APK文件。
- APK文件件:素材->APK文件夹中的文件。
3、任务编号:C5-003 构建主界面布局
3.1、相关知识点
线性布局-LinearLayout
3.2、任务描述
前置任务:C5-002
业务模块:主视图界面
任务类型:按要求写代码(功能实现)
3.3、参考效果
图1-1
图1-2
3.4、详细实现步骤
1、构建课程表主界面。
- 主界面布局文件名:layout_main.xml。
- 主界面布局选用:LinearLayout。
在主界面布局文件中增加两个View:
在主界面布局文件中增加两个View:
- 第一个视图(LinearLayout):TextView+Button
- 第二个视图:ViewPager
- ViewPager必须出现在第一个视图LinearLayout的下方
周一至周五显示课程信息(共五大节,根据系统时间自动切换界面)(如图1-1)
周六周日显示无课界面(如图1-2)
4、任务编号:C5-004-1 构建成绩显示页面布局
4.1、相关知识点
线性布局-LinearLayout
4.2、任务描述
前置任务:C5 -003
业务模块:主视图界面
构建课程表成绩页面布局
任务类型:按要求写代码(功能实现)
4.3、参考效果
图1-3
4.4、详细实现步骤
欢迎页面布局:
- 布局文件名:activity_grade.xml。
- 界面布局选用:LinearLayout。
- 背景图片设为w01.Jpg
- 在布局文件中增加40个LinearLayout:
- 每一个LinearLayout中放四个TextView,分别用来显示从校网上获取到的信息。如“学期”“课程名”“成绩”“学分”。
- 四个TextView分别占不同比重,分别是10%,60%,15%,15%,用来在显示信息的时候对齐。
5、任务编号:C5-004-2 构建登录页面布局
5.1、相关知识点
线性布局-LinearLayout
5.2、任务描述
前置任务:C5 -003
业务模块:主视图界面
构建课程表成绩页面布局
任务类型:按要求写代码(功能实现)
5.3、参考效果
图1-4
5.4、详细实现步骤
构建登录页面布局:
- 布局文件名:activity_login.xml。
- 界面布局选用:LinearLayout。
- 界面布局背景图片:background_login。
- 在布局文件中增加两个RelativeLayout:
- 第一个RelativeLayout中增加两个TextView和EditView,一个Button。 TextView为提示语“学号”和“姓名”,Button为登录按钮。
- 第二个RelativeLayout中放一个TextView ,文本设为“忘记密码”,增加点击事件“forgetPwd”。
6、任务编号:C5-004-3 构建个人信息页面布局
6.1、相关知识点
线性布局-LinearLayout
6.2、任务描述
前置任务:C5-003
业务模块:主视图界面
任务类型:按要求写代码(功能实现)
6.3、参考效果
图1-5
6.4、详细实现步骤
构建个人信息页面布局:
- 布局文件名:activity_person_info.xml。
- 界面布局选用:LinearLayout。
- 在布局文件中增加四个RelativeLayout:
- 每个RelativeLayout中都添加两个TextView,第一个显示提示信息,例:“姓名”
- 第二个用来存放从校网获取到的个人信息,如:“张三”。
7、任务编号:C5-004-4 构建关于我们页面布局
7.1、相关知识点
线性布局-LinearLayout
7.2、任务描述
前置任务:PRJ-EC-MD-03
业务模块:主视图界面
任务类型:按要求写代码(功能实现)
7.3、参考效果
图1-6
7.4、详细实现步骤
构建关于我们页面布局:
- 布局文件名:activity_about.xml。
- 界面布局选用:LinearLayout。
- 在布局文件中增加一个TextView:
- TextView中设文字“************”
8、任务编号:C5-004-5 构建欢迎页面布局
8.1、相关知识点
线性布局-LinearLayout
8.2、任务描述
前置任务:C5-003
业务模块:主视图界面
任务类型:按要求写代码(功能实现)
8.3、参考效果
图1-7
8.4、详细实现步骤
构建欢迎页面布局:
- 布局文件名:activity_splash.xml。
- 界面布局选用:RelativeLayout。
- 在布局文件中增加一个TextView:
- 背景设置为图片tb.jpg
- TextView中设欢迎语“掌上课程,方便你的生活!”
9、任务编号:C5-004-6 构建设置页面布局
9.1、相关知识点
线性布局-LinearLayout
9.2、任务描述
前置任务:C5-003
业务模块:主视图界面
任务类型:按要求写代码(功能实现)
9.3、详细实现步骤
建设置页面布局。
- 布局文件名:activity_more.xml。
- 界面布局选用:LinearLayout。
- 在布局文件中增加两个RelativeLayout:
- 第一个RelativeLayout中分别添加三个TextView和ImageView,即“个人信息”“切换账号”“查询成绩”,点击可进行页面跳转。
- 第二个RelativeLayout中分别添加三个TextView和ImageView,即“帮助与反馈”“刷新课程”“关于我们”,点击可进行页面跳转。
- 第二个RelativeLayout下方放置一个注销按钮。
10、任务编号:C5-005 解析数据源
10.1、相关知识点
jsoup包抓取网页上的数据
xUtils开源框架
10.2、任务描述
前置任务:无业务模块:数据解析
模拟登录,从校网获取到个人信息,课程信息和成绩信息。
任务类型:按要求写代码(功能实现)
10.3、详细实现步骤
1、第一步需要模拟登录
(1).检查网络是否打开
(2)在联网的情况下开启一个异步线程去请求登录。模拟登陆不能放在主线程,会阻塞主线程。
检查网络是否打开:
public void login(View view) {
if (NetWorkUtil.isNetworkConnected(this)) {
new LoginTask().execute\(usernameEditText.getText().toString()
.trim(), passwordEditText.getText().toString().trim\());
} else {
Toast.makeText(this, "当前无网络,请打开网络连接", Toast.LENGTH_SHORT).show();
}
}
异步线程:
/*采用异步技术实现登陆验证(学生登陆验证) */
public class LoginTask extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog.show();
}
@Override
protected String doInBackground(String... params) {
try {
return login(params[0], params[1]);
} catch (IOException e) {
Log.e("xkb", "" + e.getMessage());
// e.printStackTrace();
}
return "";
}
protected void onPostExecute(String result) {
dialog.dismiss();
if (result.equals("success")) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
LoginActivity.this.finish();
}else {
Toast.makeText(LoginActivity.this, "登录失败,请核对学号和密码", Toast.LENGTH_LONG).show();
}
}
}
模拟登录:
public String login(String username, String password) throws IOException {
String cookie = new String();
String tag = "";
// 验证用户名和密码
Connection con = Jsoup.connect(Util.LOGIN_URL)
.data("userName", username).data("password", password)
.timeout(5000);
con.post();
cookie = con.response().cookie("iPlanetDirectoryPro");
if (cookie != null) {
/* 获取个人信息 课程信息*/
getUserInfo(cookie);
tag = "success";
}
return tag;
}
2.第2步开始获取想要的信息
(1).获取个人信息:需要保存网页中的cookie
/* 获取个人信息*/
private void getUserInfo(String cookie) throws IOException {
// 开始获取个人信息
Connection con = Jsoup.connect(Util.USER_INFO_URL)
.cookie("iPlanetDirectoryPro", cookie).timeout(5000);
//保存网页中的cookie
String cookie2 = con.response().cookie("JSESSIONID");
//获取到的信息保存在文档Document中
Document yuanma = con.get();
//通过筛选来抓取有用的信息
Elements div = yuanma.select("div.composer");
Elements lis = div.select("li");
// 存放个人信息的数组
String[] str = new String[10];
int i = 0;
for (Element li : lis) {
String personInfo = li.text();
str[i] = personInfo;
i++;
}
editor.putString("name", str[0].substring(0, str[0].indexOf(",")).trim());//名字放入到key值为”name”的键值对中
editor.putString("number", str[2].substring(str[2].indexOf(":") + 1).trim()); //学号放入到key值为”number”的键值对中
editor.putString("class", str[3].substring(str[3].indexOf(":") + 1).trim()); //班级放入到key值为”class”的键值对中
editor.putString("depart", str[4].substring(str[4].indexOf(":") + 1).trim()); //院系放入到key值为”depart”的键值对中
editor.commit();
}
(2).获取课程信息和成绩信息和获取个人信息步骤一样,须模拟登陆保存cookie才可以抓取。
而抓取的方式有所不同。
获取课程信息:
Document doc = con.get();
//课程信息在表格table_kc中
Elements kechengbiaoElement = doc.select("table.table_kc");
//课程保存在包含br>标签的div标签中
Elements kechengElements = kechengbiaoElement.select("div:has(br)");
获取成绩信息:
Document doc = con.get();
Elements kechengbiaoElement = doc.select("table.table_kscj");
//成绩保存在包含td标签的tr标签中
Elements trs = kechengbiaoElement.select("tr");
for (int i = 0; i < trs.size(); i++) {
Elements tds = trs.get(i).select("td");
//只抓取一个tr标签中的第2.3.5.8个td标签,即学期,课程,成绩和学分
String text= tds.get(1).text();
String text1= tds.get(2).text();
String text2= tds.get(4).text();
String text3= tds.get(7).text();
}
11、任务编号:C5-006 解析系统时间
11.1、相关知识点
xUtils开源框架
11.2、任务描述
前
置任务:无
业务模块:解析当前系统时间,并转换为需要的格式
任务类型:按要求写代码(功能实现)
11.3、详细实现步骤
第一步需要获取当前系统时间
/*获取当前周是第几周*/
@SuppressLint("SimpleDateFormat")
public static long getCurrentWeek() {
Date data = new Date();//获取当前系统时间
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//解析时间格式
long to = 0;
long from = 0;
String currentData = df.format(data);
try {
from = df.parse(Util.SCHOOL_START_DATE).getTime();
to = df.parse(currentData).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
long currentWeek = ((to - from) / (1000 * 60 * 60 * 24) + 1) / 7 + 1;// 计算当前周
return currentWeek;
}
/* 获取今天是星期几*/
public static String getCurrentDay() {
long time=System.currentTimeMillis();
Date date=new Date(time);
SimpleDateFormat format=new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 EEEE");
format=new SimpleDateFormat("EEEE"); //只获取周几(形式是星期*)
return format.format(date);
}
12、任务编号:C5-007 数据封装
12.1、相关知识点
将数据封装入对象中
12.2、任务描述
前
置任务:C5-005,C5-006
业务模块:数据解析加封装
设计并定义保存数据的实体类。
任务类型:按要求写代码(功能实现)
12.3、详细实现步骤
1、设计并定义保存课程数据的CourseEntity实体类
- 实体有course, teacher, week, classroom,重写他们的get和set方法
2、设计并定义保存课程数据的BaseEntity实体类
- 实体有Id,重写他的get和set方法
3、用Adapter适配器显示每一天课程。
CourseAdapter继承BaseAdapter:
- 先获取到页面布局
// 如果缓存convertView为空,则需要创建View if (convertView == null) { holder = new ViewHolder(); // 根据自定义的Item布局加载布局 convertView = mInflater.inflate(R.layout.list_item, null); holder.jieci = (TextView) convertView.findViewById(R.id.textView01); holder.teacher = (TextView) convertView.findViewById(R.id.textView02); holder.week = (TextView) convertView.findViewById(R.id.textView03); holder.course = (TextView) convertView.findViewById(R.id.textView04); holder.classroom = (TextView) convertView.findViewById(R.id.textView05);
- 根据周几来显示相应的课程信息
holder.jieci.setText(jieciStrings[position]); holder.course.setText(mDatas.get(position).getCourse()); holder.teacher.setText(mDatas.get(position).getTeacher()); holder.week.setText(mDatas.get(position).getWeek()); holder.classroom.setText(mDatas.get(position).getClassroom());
MyPagerAdapter继承FragmentPagerAdapter
- 重写所有的方法
13、任务编号:C5-008 课程信息显示
13.1、相关知识点
SimpleAdapter
13.2、任务描述
前置任务:C5-007
业务模块:课程显示
根据星期几显示相应课程
任务类型:按要求写代码(功能实现)
13.3、详细实现步骤
1、 初始化屏幕(包括周一至周五五个页面)。
private void init() {
// 初始化屏幕宽度
DisplayMetrics outmMetrics = new DisplayMetrics();
getWindow().getWindowManager().getDefaultDisplay().getMetrics(outmMetrics);
screenWidth = outmMetrics.widthPixels;
initView();
// 设置title : 周次
currentWeek = DateUtil.getCurrentWeek();
courseText.setText("课程表(第" + currentWeek + "周)");
Log.i("chen", "currentWeek--->" + currentWeek);
}
private void initView() {
// 初始化五个页面
Fragment02 fragment0 = new Fragment02();
Fragment01 fragment1 = new Fragment01(0);
Fragment01 fragment2 = new Fragment01(1);
Fragment01 fragment3 = new Fragment01(2);
Fragment01 fragment4 = new Fragment01(3);
Fragment01 fragment5 = new Fragment01(4);
Fragment02 fragment6 = new Fragment02();
fragments.add(fragment0);
fragments.add(fragment1);
fragments.add(fragment2);
fragments.add(fragment3);
fragments.add(fragment4);
fragments.add(fragment5);
fragments.add(fragment6);
fragSize = fragments.size();
// 初始化顶部tab
firstTab = (LinearLayout) findViewById(R.id.tab_first);
secondTab = (LinearLayout) findViewById(R.id.tab_second);
thirdTab = (LinearLayout) findViewById(R.id.tab_third);
fourTab = (LinearLayout) findViewById(R.id.tab_four);
fiveTab = (LinearLayout) findViewById(R.id.tab_five);
sixTab = (LinearLayout) findViewById(R.id.tab_six);
sevenTab = (LinearLayout) findViewById(R.id.tab_seven);
// 给tab设置点击事件
firstTab.setOnClickListener(tabClickListener);
secondTab.setOnClickListener(tabClickListener);
thirdTab.setOnClickListener(tabClickListener);
fourTab.setOnClickListener(tabClickListener);
fiveTab.setOnClickListener(tabClickListener);
sixTab.setOnClickListener(tabClickListener);
sevenTab.setOnClickListener(tabClickListener);
initTabUnderLine();
firstText = (TextView) findViewById(R.id.text_first);
secondText = (TextView) findViewById(R.id.text_second);
thirdText = (TextView) findViewById(R.id.text_third);
fourText = (TextView) findViewById(R.id.text_four);
fiveText = (TextView) findViewById(R.id.text_five);
sixText = (TextView) findViewById(R.id.text_six);
sevenText = (TextView) findViewById(R.id.text_seven);
courseText = (TextView) findViewById(R.id.text_course);
moreText = (TextView) findViewById(R.id.text_more);
viewPager = (ViewPager) findViewById(R.id.viewpager);
pagerAdapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
viewPager.setAdapter(pagerAdapter);
viewPager.setOnPageChangeListener(pageChangeListener);
/**
* 根据当前是星期几,来显示星期几的课程信息
*/
setCurrentPage();
viewPager.setOffscreenPageLimit(fragSize);
}
2.课程信息放入实体中显示
/* 根据当前是星期几,来显示星期几的课程信息*/
private void setCurrentPage() {
// 获取当前星期几
currentDay = DateUtil.getCurrentDay().toString().trim();
Log.i("chen", "currentDay--->" + currentDay);
if (currentDay.equals("星期日")) {
viewPager.setCurrentItem(0);//如果是星期日,则设置显示第0个页面
} else if (currentDay.equals("星期一")) {
viewPager.setCurrentItem(1);
} else if (currentDay.equals("星期二")) {
viewPager.setCurrentItem(2);
} else if (currentDay.equals("星期三")) {
viewPager.setCurrentItem(3);
} else if (currentDay.equals("星期四")) {
viewPager.setCurrentItem(4);
} else if (currentDay.equals("星期五")) {
viewPager.setCurrentItem(5);
} else if (currentDay.equals("星期六")) {
Log.i("chen", "currentDay--->" + currentDay);
viewPager.setCurrentItem(6);
}
}
3.设置tab标题颜色
private void resetTabTextView() {
firstText.setTextColor(getResources().getColor(R.color.black));
secondText.setTextColor(getResources().getColor(R.color.black));
thirdText.setTextColor(getResources().getColor(R.color.black));
fourText.setTextColor(getResources().getColor(R.color.black));
fiveText.setTextColor(getResources().getColor(R.color.black));
sixText.setTextColor(getResources().getColor(R.color.black));
sevenText.setTextColor(getResources().getColor(R.color.black));
}
14、任务编号:C5-009 个人信息显示
14.1、相关知识点
自定义适配器(简单)
14.2、任务描述
前置任务:C5-007
业务模块:个人信息
任务类型1:按要求写代码(功能实现)
14.3、参考效果
图1-5
14.4、详细实现步骤
1.先获取到页面布局
- 初始化所有的控件。
private void initViews() {
name = (TextView) findViewById(R.id.pinfo_name);
num = (TextView) findViewById(R.id.pinfo_num);
pclass = (TextView) findViewById(R.id.pinfo_class);
yuanxi = (TextView) findViewById(R.id.pinfo_yuanxi);
btnBack = (Button) findViewById(R.id.btn_back);
}
2.从保存信息的文档中取出所需信息,并放入页面显示
int MODE = MODE_PRIVATE;
SharedPreferences sharedPreferences = getSharedPreferences(Util.PREFERENCE_NAME, MODE);
name.setText(sharedPreferences.getString("name", ""));//名字保存在key值为”name”的键值对中
num.setText(sharedPreferences.getString("number", ""));//学号
pclass.setText(sharedPreferences.getString("class", ""));//学校类别(本专)
yuanxi.setText(sharedPreferences.getString("depart", ""));//院系
15、任务编号:C5-010 成绩信息显示
15.1、相关知识点
自定义控件以及信息取放
15.2、任务描述
前置任务:C5-007
业务模块:成绩显示
显示学期,课程,成绩和学分
1-1、 各控件所占宽度
1-2、 各布局的排版
任务类型:按要求写代码(功能实现)
15.3、参考效果
图1-3
15.4、详细实现步骤
1.获取到页面布局及相应控件
private void initViews() {
back=(Button) findViewById(R.id.btn_back);//返回按钮
TV1=(TextView) findViewById(R.id.tv1);
TV2=(TextView) findViewById(R.id.tv2);
TV3=(TextView) findViewById(R.id.tv3);
TV4=(TextView) findViewById(R.id.tv4);
TV5=(TextView) findViewById(R.id.tv5);
TV6=(TextView) findViewById(R.id.tv6);
TV7=(TextView) findViewById(R.id.tv7);
TV8=(TextView) findViewById(R.id.tv8);
TV9=(TextView) findViewById(R.id.tv9);
}
2.从保存信息的文档中拿出成绩信息,放入页面显示
int MODE = MODE_PRIVATE;
//获取到文档
SharedPreferences sharedPreferences = getSharedPreferences(Util.PREFERENCE_NAME, MODE);
//第一门课程的信息
TV1.setText(sharedPreferences.getString("chengjia"+1, ""));//学期
TV_1.setText(sharedPreferences.getString("chengjib"+1, ""));//课程名
TV_01.setText(sharedPreferences.getString("chengjic"+1, ""));//成绩
TV_111.setText(sharedPreferences.getString("chengjid"+1, ""));//学分
//第二门课程的信息
TV2.setText(sharedPreferences.getString("chengjia"+2, ""));//学期
TV_2.setText(sharedPreferences.getString("chengjib"+2, ""));//课程名
TV_02.setText(sharedPreferences.getString("chengjic"+2, ""));//成绩
TV_222.setText(sharedPreferences.getString("chengjid"+2, ""));//学分